﻿using Codemonk.Common.Configuring;
using System;
using Codemonk.Common.Caching;

namespace Codemonk.Common.Injection
{
    /// <summary>
    /// 系统默认对象构建器
    /// 在系统启动时,将使用此类创建一个被配置的对象构建器
    /// 在上述的对象构建器创建之后,这个类就失去用途了
    /// </summary>
    public static class DefaultObjectBuilder
    {
        private class InnerObjectBuilder : Configurable, IObjectBuilder, IConfigurable
        {
            private ICacheCollection<string, IObjectBuilder> objectCache = new DictionaryCache<string, IObjectBuilder>();
            private ICacheCollection<string, string> valueCache = new DictionaryCache<string, string>();

            private bool initializated = false;

            public override void Initialization()
            {
                if (initializated) return; initializated = true;
                var objectbuilders = Reader.ReadDouble("/codemonk/objectbuilders//objectbuilder", "@name", "@classpath");
                if (objectbuilders == null) throw AssemblyConfigException.Instance;
                foreach (var objectbuilder in objectbuilders)
                {
                    var key = objectbuilder.Item1;
                    var value = objectbuilder.Item2;
                    if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value)) continue;
                    valueCache.Set(key, value);
                }
            }

            public object Resolve(string name)
            {
                Initialization();
                IObjectBuilder builder;
                if (objectCache.TryGet(name, out builder)) return builder;
                string classpath;
                if (valueCache.TryGet(name, out classpath))
                {
                    Type type = classpath.AsType();
                    try
                    {
                        if (type == typeof(ObjectBuilder)) builder = ObjectBuilder.Instance;
                        else builder = Activator.CreateInstance(type) as IObjectBuilder;
                        objectCache.Set(name, builder);
                        return builder;
                    }
                    catch { }
                }
                return null;
            }

            public T Resolve<T>(string name = null)
            {
                if (typeof(T) != typeof(IObjectBuilder)) throw new NotSupportedException();
                return (T)Resolve(name);
            }
        }

        static DefaultObjectBuilder()
        {
            builder = new InnerObjectBuilder { Reader = new AssemblyConfigReader() };
        }

        private static InnerObjectBuilder builder;

        public static IObjectBuilder ResolveObjectBuilder(string name = "default")
        {
            var obj = builder.Resolve(name) as IObjectBuilder;
            if (obj == null) return ObjectBuilder.Instance;
            else return obj;
        }
    }
}
